home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / c / fortify.lha / zfortify.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-03  |  22.1 KB  |  896 lines

  1. // ZFortify.cpp - A fortified shell for new and delete.
  2.  
  3. //     The  minimum  you  need  to  do for ZFortify is to define the symbol
  4. // ZFORTIFY,  and  link  zfortify.o.   Each source file should also include
  5. // "zfortify.hpp",  but  this  isn't strictly necessary.  If a file doesn't
  6. // #include  "Fortify.hpp",  then it's allocations will still be fortified,
  7. // however  you  will not have any source-code details in any of the output
  8. // messages  (this will be the case for all libraries, etc, unless you have
  9. // the source for the library and can recompile it with Fortify).
  10. //     If  you  do  not  have  stdout  available,  you  may  wish to set an
  11. // alternate  output  function,  or  turn  on  the  AUTOMATIC_LOGFILE.  See
  12. // ZFortify_SetOutputFunc() and AUTOMATIC_LOGFILE, below.
  13. // 
  14. // None  of  the  functions  in  this  file should be called directly; they
  15. // should be called through the macros defined in ZFortify.hpp.
  16.  
  17. #ifdef ZFORTIFY
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <math.h>
  22. #include <time.h>
  23. #include <ctype.h>
  24.  
  25. #define  ZFORTIFY_CPP   // So ZFortify.hpp knows to not define the ZFortify macros 
  26. #include "ZFortify.hpp"
  27.  
  28. // the user's options 
  29. #include "ufortify.hpp"   
  30.  
  31. struct Header
  32. {
  33.     char          *File;     // The sourcefile of the caller 
  34.     unsigned long  Line;     // The sourceline of the caller
  35.     size_t         Size;     // The size of the new'd block
  36.     struct Header *Prev;     // List pointers
  37.     struct Header *Next;     //
  38.     int            Scope;    // Scope level this block was allocated in
  39.     int            Checksum; // For validating the Header structure; see ChecksumHeader()
  40. };
  41.  
  42. // Local prototypes
  43. static int  CheckBlock(struct Header *h, char *file, unsigned long line);
  44. static int  CheckFortification(unsigned char *ptr, unsigned char value, size_t size);
  45. static void SetFortification(unsigned char *ptr, unsigned char value, size_t size);
  46. static void OutputFortification(unsigned char *ptr, unsigned char value, size_t size);
  47. static int  IsHeaderValid(struct Header *h);
  48. static void MakeHeaderValid(struct Header *h);
  49. static int  ChecksumHeader(struct Header *h);
  50. static int  IsOnList(struct Header *h);
  51. static void OutputMemory(struct Header *h);
  52. static void OutputHeader(struct Header *h);
  53. static void OutputLastVerifiedPoint(void);
  54.  
  55. // The default output function
  56. static void st_DefaultOutput(const char *String)
  57. {
  58.     printf(String);
  59. }
  60.  
  61. static struct Header *st_Head = 0; // Head of alloc'd memory list 
  62. static ZFortify_OutputFuncPtr  st_Output = st_DefaultOutput; // Output function for errors 
  63. static char st_Buffer[256];       // Temporary buffer for sprintf's 
  64. static int st_Disabled = 0;       // If true, ZFortify is inactive 
  65. static int st_NewFailRate = 0;    // % of the time to false fail new
  66.  
  67. static char          *st_LastVerifiedFile = "unknown";
  68. static unsigned long  st_LastVerifiedLine = 0;
  69.  
  70. static char             *st_Delete_File = 0;
  71. static unsigned long  st_Delete_Line = 0;
  72.  
  73. static int            st_Scope = 0;
  74.  
  75. // operator new() - Allocates a block of memory, with extra bits for
  76. //                  misuse protection/detection. 
  77. // Features:
  78. //     +  Adds the new'd memory onto ZFortify's own private list.
  79. //        (With a checksum'd header to detect corruption of the memory list)
  80. //     +  Places sentinals on either side of the user's memory with
  81. //        known data in them, to detect use outside of the bounds
  82. //        of the block
  83. //     +  Initializes the new'd memory to some "nasty" value, so code
  84. //        can't rely on it's contents.
  85. //     +  Can check all sentinals on every NEW.
  86. //     +  Can generate a warning message on a NEW fail.
  87. //     +  Can randomly "fail" at a set fail rate
  88. void *ZFORTIFY_STORAGE
  89. operator new(size_t size) 
  90.     return operator new(size, "new", 0); 
  91. }
  92.  
  93. #ifdef ZFORTIFY_PROVIDE_ARRAY_NEW
  94.  
  95. void *ZFORTIFY_STORAGE
  96. operator new[](size_t size) 
  97.     return operator new(size, "new[]", 0); 
  98. }
  99.  
  100. void *ZFORTIFY_STORAGE
  101. operator new[](size_t size, char *file, unsigned long line)
  102. {
  103.     return operator new(size, file, line);
  104. }
  105.  
  106. #endif // ZFORTIFY_PROVIDE_ARRAY_NEW
  107.  
  108. void *ZFORTIFY_STORAGE
  109. operator new(size_t size, char *file, unsigned long line)
  110. {
  111.     unsigned char *ptr;
  112.     struct Header *h;
  113.  
  114.     ZFORTIFY_LOCK();
  115.  
  116.     if(st_Disabled)
  117.     {
  118.         ptr = (unsigned char *)malloc(size);
  119.         ZFORTIFY_UNLOCK();
  120.         return(ptr);
  121.     }
  122.  
  123. #ifdef CHECK_ALL_MEMORY_ON_NEW
  124.     ZFortify_CheckAllMemory(file, line);
  125. #endif  
  126.  
  127.     if(size == 0)
  128.     {
  129. #ifdef WARN_ON_ZERO_NEW
  130.         sprintf(st_Buffer, "\nZFortify: %s.%ld\n         new(0) attempted failed\n",
  131.                            file, line);
  132.         st_Output(st_Buffer);
  133. #endif
  134.  
  135.         ZFORTIFY_UNLOCK();
  136.         return(0);       
  137.     }
  138.  
  139.     if(st_NewFailRate > 0)
  140.     {
  141.         if(rand() % 100 < st_NewFailRate)
  142.         {
  143. #ifdef WARN_ON_FALSE_FAIL
  144.             sprintf(st_Buffer, "\nZFortify: %s.%ld\n         new(%ld) \"false\" failed\n",
  145.                                file, line, (unsigned long)size);
  146.             st_Output(st_Buffer);
  147. #endif
  148.             ZFORTIFY_UNLOCK();
  149.             return(0);
  150.         }
  151.     }
  152.   
  153. #ifdef WARN_ON_SIZE_T_OVERFLOW               
  154.     {
  155.         size_t private_size = sizeof(struct Header) 
  156.                             + ZFORTIFY_BEFORE_SIZE + size + ZFORTIFY_AFTER_SIZE;
  157.  
  158.         If(private_size < size) /* Check to see if the added baggage is larger than size_t */
  159.         {
  160.             sprintf(st_Buffer, "\nZFortify: %s.%ld\n         new(%ld) has overflowed size_t.\n",
  161.                                 file, line, (unsigned long)size);
  162.             st_Output(st_Buffer);
  163.             ZFORTIFY_UNLOCK();
  164.             return(0);
  165.         }                              
  166.     }
  167. #endif                              
  168.  
  169.     // new the memory, including the space for the header 
  170.       // and fortification buffers (well, we fake it with malloc).
  171.     ptr = (unsigned char *)malloc(sizeof(struct Header) + ZFORTIFY_BEFORE_SIZE + size + ZFORTIFY_AFTER_SIZE);
  172.     if(!ptr)
  173.     {
  174. #ifdef WARN_ON_NEW_FAIL
  175.         sprintf(st_Buffer, "\nZFortify: %s.%ld\n         new(%ld) failed\n",
  176.                             file, line, (unsigned long)size);
  177.         st_Output(st_Buffer);
  178. #endif
  179.  
  180.         ZFORTIFY_UNLOCK();
  181.         return(0);       
  182.     }
  183.  
  184.     // Initialize and validate the header
  185.     h = (struct Header *)ptr;
  186.  
  187.     h->Size  = size;
  188.   
  189.     h->File  = file;
  190.     h->Line  = line;  
  191.  
  192.     h->Next  = st_Head;
  193.     h->Prev  = 0;
  194.     h->Scope = st_Scope;
  195.  
  196.     if(st_Head)
  197.     {
  198.         st_Head->Prev = h;
  199.         MakeHeaderValid(st_Head);  
  200.     }
  201.  
  202.     st_Head = h;
  203.   
  204.     MakeHeaderValid(h);
  205.  
  206.     // Initialize the fortifications
  207.     SetFortification(ptr + sizeof(struct Header), ZFORTIFY_BEFORE_VALUE, ZFORTIFY_BEFORE_SIZE);
  208.     SetFortification(ptr + sizeof(struct Header) + ZFORTIFY_BEFORE_SIZE + size,
  209.                      ZFORTIFY_AFTER_VALUE, ZFORTIFY_AFTER_SIZE);
  210.  
  211. #ifdef FILL_ON_NEW 
  212.     // Fill the actual user memory
  213.     SetFortification(ptr + sizeof(struct Header) + ZFORTIFY_BEFORE_SIZE, FILL_ON_NEW_VALUE, size);
  214. #endif
  215.  
  216.     ZFORTIFY_UNLOCK();
  217.  
  218.     // We return the address of the user's memory, not the start of the block,
  219.     // which points to our magic cookies
  220.     return(ptr + sizeof(struct Header) + ZFORTIFY_BEFORE_SIZE);
  221. }
  222.  
  223. // operator delete() - This delete must be used for all memory allocated with
  224. //                     the ZFortify new()
  225. //
  226. //   Features:
  227. //     + Pointers are validated before attempting a delete - the pointer
  228. //       must point to a valid new'd bit of memory.
  229. //     + Detects attempts at deleting the same block of memory twice
  230. //     + Can clear out memory as it is freed, to prevent code from using
  231. //       the memory after it's been freed.
  232. //     + Checks the sentinals of the memory being freed.
  233. //     + Can check the sentinals of all memory.
  234. int ZFORTIFY_STORAGE
  235. ZFortify_PreDelete(char *file, unsigned long line)
  236. {
  237.     // Don't change the delete source code pointer if we already have some information,
  238.     // cause if we're doing a delete inside a delete, the highest level delete will 
  239.     // probably be the most useful.
  240.     if(st_Delete_File == 0)
  241.     {
  242.         st_Delete_File = file;
  243.         st_Delete_Line = line;   
  244.     }    
  245.     return 1;
  246. }
  247.  
  248. void ZFORTIFY_STORAGE
  249. operator delete(void *uptr)
  250. {
  251.     unsigned char *ptr = (unsigned char *)uptr - sizeof(struct Header) - ZFORTIFY_BEFORE_SIZE;
  252.     struct Header *h = (struct Header *)ptr;
  253.     char *file;
  254.     unsigned long line;    
  255.  
  256.     // It is defined to be harmless to delete 0
  257.     if(uptr == 0)
  258.         return;
  259.  
  260.     ZFORTIFY_LOCK();
  261.  
  262.     if(st_Disabled)
  263.     {
  264.         free(uptr);
  265.         ZFORTIFY_UNLOCK();
  266.         return;
  267.     }
  268.  
  269.     if(st_Delete_File)
  270.     {
  271.         file = st_Delete_File;
  272.         line = st_Delete_Line;
  273.     
  274.         st_Delete_File = 0;
  275.     }
  276.     else
  277.     {
  278.         file = "delete";
  279.         line = 0;
  280.     }
  281.  
  282. #ifdef CHECK_ALL_MEMORY_ON_DELETE
  283.     ZFortify_CheckAllMemory(file, line);
  284. #endif  
  285.  
  286. #ifdef PARANOID_DELETE
  287.     if(!IsOnList(h))
  288.     {
  289.         sprintf(st_Buffer,
  290.                 "\nZFortify: %s.%ld\n         Invalid pointer, corrupted header, or possible free twice\n",
  291.                 file, line);
  292.         st_Output(st_Buffer);
  293.         OutputLastVerifiedPoint();
  294.         goto fail;
  295.     }
  296. #endif
  297.  
  298.     if(!CheckBlock(h, file, line))
  299.         goto fail;
  300.     
  301.     // Remove the block from the list
  302.     if(h->Prev)
  303.     {
  304.         if(!CheckBlock(h->Prev, file, line))
  305.             goto fail;
  306.       
  307.         h->Prev->Next = h->Next;
  308.         MakeHeaderValid(h->Prev);
  309.     }
  310.     else
  311.         st_Head = h->Next;
  312.  
  313.     if(h->Next)
  314.     {
  315.         if(!CheckBlock(h->Next, file, line))
  316.             goto fail;
  317.  
  318.         h->Next->Prev = h->Prev;
  319.         MakeHeaderValid(h->Next);    
  320.     }    
  321.  
  322. #ifdef FILL_ON_DELETE
  323.     // Nuke out all memory that is about to be freed
  324.     SetFortification(ptr, FILL_ON_DELETE_VALUE, 
  325.                      sizeof(struct Header) + ZFORTIFY_BEFORE_SIZE + h->Size + ZFORTIFY_AFTER_SIZE);
  326. #endif               
  327.  
  328.     // And do the actual free
  329.     free(ptr);
  330.     ZFORTIFY_UNLOCK();
  331.     return;
  332.  
  333. fail:
  334.     sprintf(st_Buffer, "         delete(%p) failed\n", uptr);
  335.     st_Output(st_Buffer);  
  336.     ZFORTIFY_UNLOCK();
  337. }
  338.  
  339. // ZFortify_CheckPointer() - Returns true if the uptr points to a valid
  340. // piece of ZFortify_new()'d memory. The memory must be on the new'd
  341. // list, and it's sentinals must be in tact.
  342. // If anything is wrong, an error message is issued.
  343. //
  344. //   (Note - if ZFortify is disabled, this function always returns true).
  345. int ZFORTIFY_STORAGE
  346. ZFortify_CheckPointer(void *uptr, char *file, unsigned long line)
  347. {
  348.     unsigned char *ptr = (unsigned char *)uptr - sizeof(struct Header) - ZFORTIFY_BEFORE_SIZE;
  349.     int r;
  350.   
  351.     if(st_Disabled)
  352.         return(1);
  353.  
  354.     ZFORTIFY_LOCK();
  355.  
  356.     if(!IsOnList((struct Header *)ptr))
  357.     {
  358.         sprintf(st_Buffer, "\nZFortify: %s.%ld\n         Invalid pointer or corrupted header detected (%p)\n",
  359.                             file, line, uptr);
  360.         st_Output(st_Buffer);
  361.         ZFORTIFY_UNLOCK();
  362.         return(0);
  363.     }
  364.  
  365.     r = CheckBlock((struct Header *)ptr, file, line);
  366.     ZFORTIFY_UNLOCK();
  367.     return r;
  368. }
  369.  
  370. // ZFortify_SetOutputFunc(ZFortify_OutputFuncPtr Output) - Sets the function used to
  371. // output all error and diagnostic messages by ZFortify. The output function 
  372. // takes a single unsigned char * argument, and must be able to handle newlines.
  373. //     The function returns the old pointer.
  374. ZFortify_OutputFuncPtr ZFORTIFY_STORAGE
  375. ZFortify_SetOutputFunc(ZFortify_OutputFuncPtr Output)
  376. {
  377.     ZFortify_OutputFuncPtr Old = st_Output;
  378.  
  379.     st_Output = Output;
  380.   
  381.     return(Old);
  382. }
  383.  
  384. // ZFortify_SetNewFailRate(int Percent) - ZFortify_new() will make the
  385. // new attempt fail this Percent of the time, even if the memory is
  386. // available. Useful to "stress-test" an application. Returns the old
  387. //  value. The fail rate defaults to 0.
  388. int ZFORTIFY_STORAGE
  389. ZFortify_SetNewFailRate(int Percent)
  390. {
  391.     int Old = st_NewFailRate;
  392.   
  393.     st_NewFailRate = Percent;
  394.   
  395.     return(Old);
  396. }
  397.  
  398.  
  399. // ZFortify_CheckAllMemory() - Checks the sentinals of all new'd memory.
  400. // Returns the number of blocks that failed. 
  401. //
  402. //  (If ZFortify is disabled, this function always returns 0).
  403. int ZFORTIFY_STORAGE
  404. ZFortify_CheckAllMemory(char *file, unsigned long line)
  405. {
  406.     struct Header *curr = st_Head;
  407.     int count = 0;
  408.  
  409.     if(st_Disabled)
  410.         return(0);
  411.  
  412.     ZFORTIFY_LOCK();
  413.  
  414.     while(curr)
  415.     {
  416.         if(!CheckBlock(curr, file, line))
  417.             count++;
  418.  
  419.         curr = curr->Next;      
  420.     }
  421.   
  422.     if(count == 0)
  423.     {
  424.         st_LastVerifiedFile = file;
  425.         st_LastVerifiedLine = line;
  426.     }    
  427.  
  428.     ZFORTIFY_UNLOCK();
  429.     return(count);
  430. }
  431.  
  432. // ZFortify_EnterScope - enters a new ZFortify scope level. 
  433. // returns the new scope level.
  434. int ZFORTIFY_STORAGE
  435. ZFortify_EnterScope(char */*file*/, unsigned long /*line*/)
  436. {
  437.     return(++st_Scope);
  438. }
  439.  
  440. // ZFortify_LeaveScope - leaves a ZFortify scope level,
  441. // also prints a memory dump of all non-freed memory that was allocated
  442. // during the scope being exited.
  443. int ZFORTIFY_STORAGE
  444. ZFortify_LeaveScope(char *file, unsigned long line)
  445. {
  446.     struct Header *curr = st_Head;
  447.     int count = 0;
  448.     unsigned long size = 0;
  449.  
  450.     if(st_Disabled)
  451.         return(0);
  452.  
  453.     ZFORTIFY_LOCK();
  454.  
  455.     st_Scope--;
  456.     while(curr)
  457.     {
  458.         if(curr->Scope > st_Scope)
  459.         {
  460.             if(count == 0)
  461.             {
  462.                 sprintf(st_Buffer, "\nZFortify: Memory Dump at %s.%ld\n", file, line);
  463.                 st_Output(st_Buffer);
  464.                 OutputLastVerifiedPoint();
  465.                 sprintf(st_Buffer, "%11s %8s %s\n", "Address", "Size", "Allocator");
  466.                 st_Output(st_Buffer);
  467.             }    
  468.                                 
  469.             OutputHeader(curr);
  470.             count++;
  471.             size += curr->Size;
  472.         }
  473.  
  474.         curr = curr->Next;      
  475.     }
  476.  
  477.     if(count)
  478.     {
  479.         sprintf(st_Buffer, "%11s %8ld bytes overhead\n", "and",
  480.                         (unsigned long)(count * (sizeof(struct Header) + ZFORTIFY_BEFORE_SIZE + ZFORTIFY_AFTER_SIZE)));
  481.                         st_Output(st_Buffer);
  482.  
  483.         sprintf(st_Buffer,"%11s %8ld bytes in %d blocks\n", "total", size, count);
  484.         st_Output(st_Buffer);
  485.     }
  486.  
  487.     ZFORTIFY_UNLOCK();
  488.     return(count);
  489. }
  490.  
  491. // ZFortify_OutputAllMemory() - Outputs the entire list of currently
  492. // new'd memory. For each new'd block is output it's Address,
  493. // Size, and the SourceFile and Line that allocated it.
  494. //
  495. // If there is no memory on the list, this function outputs nothing.
  496. //
  497. // It returns the number of blocks on the list, unless ZFortify has been
  498. // disabled, in which case it always returns 0.
  499. int ZFORTIFY_STORAGE
  500. ZFortify_OutputAllMemory(char *file, unsigned long line)
  501. {
  502.     struct Header *curr = st_Head;
  503.     int count = 0;
  504.     unsigned long size = 0;
  505.  
  506.     if(st_Disabled)
  507.         return(0);
  508.  
  509.     ZFORTIFY_LOCK();
  510.  
  511.     if(curr)
  512.     {
  513.         sprintf(st_Buffer, "\nZFortify: Memory Dump at %s.%ld\n", file, line);
  514.         st_Output(st_Buffer);
  515.         OutputLastVerifiedPoint();
  516.         sprintf(st_Buffer, "%11s %8s %s\n", "Address", "Size", "Allocator");
  517.         st_Output(st_Buffer);
  518.                                 
  519.         while(curr)
  520.         {
  521.             OutputHeader(curr);
  522.             count++;
  523.             size += curr->Size;
  524.             curr = curr->Next;      
  525.         }
  526.                      
  527.         sprintf(st_Buffer, "%11s %8ld bytes overhead\n", "and", 
  528.             (unsigned long)(count * (sizeof(struct Header) + ZFORTIFY_BEFORE_SIZE + ZFORTIFY_AFTER_SIZE)));
  529.         st_Output(st_Buffer);
  530.  
  531.         sprintf(st_Buffer,"%11s %8ld bytes in %d blocks\n", "total", size, count);  
  532.         st_Output(st_Buffer);
  533.     }
  534.   
  535.     ZFORTIFY_UNLOCK();
  536.     return(count);
  537. }
  538.  
  539. // ZFortify_DumpAllMemory(Scope) - Outputs the entire list of currently
  540. // new'd memory within the specified scope. For each new'd block is output
  541. // it's Address, Size, the SourceFile and Line that allocated it, a hex dump
  542. // of the contents of the memory and an ascii dump of printable characters.
  543. //
  544. // If there is no memory on the list, this function outputs nothing.
  545. //
  546. // It returns the number of blocks on the list, unless ZFortify has been
  547. // disabled, in which case it always returns 0.
  548. int ZFORTIFY_STORAGE
  549. ZFortify_DumpAllMemory(int scope, char *file, unsigned long line)
  550. {
  551.     struct Header *curr = st_Head;
  552.     int count = 0;
  553.     unsigned long size = 0;
  554.  
  555.     if(st_Disabled)
  556.         return(0);
  557.  
  558.     ZFORTIFY_LOCK();
  559.  
  560.     while(curr)
  561.     {
  562.         if(curr->Scope >= scope)
  563.         {
  564.             if(count == 0)
  565.             {
  566.                 sprintf(st_Buffer, "\nZFortify: Memory Dump at %s.%ld\n", file, line);
  567.                 st_Output(st_Buffer);
  568.                 OutputLastVerifiedPoint();
  569.                 sprintf(st_Buffer, "%11s %8s %s\n", "Address", "Size", "Allocator");
  570.                 st_Output(st_Buffer);
  571.             }
  572.  
  573.             OutputHeader(curr);
  574.             OutputMemory(curr);
  575.             st_Output("\n");
  576.             count++;
  577.             size += curr->Size;
  578.         }
  579.  
  580.         curr = curr->Next;
  581.     }
  582.  
  583.     if(count)
  584.     {
  585.         sprintf(st_Buffer, "%11s %8ld bytes overhead\n", "and",
  586.                         (unsigned long)(count * (sizeof(struct Header) + ZFORTIFY_BEFORE_SIZE + ZFORTIFY_AFTER_SIZE)));
  587.                         st_Output(st_Buffer);
  588.  
  589.         sprintf(st_Buffer,"%11s %8ld bytes in %d blocks\n", "total", size, count);
  590.         st_Output(st_Buffer);
  591.     }
  592.  
  593.     ZFORTIFY_UNLOCK();
  594.     return(count);
  595. }
  596.  
  597. // ZFortify_Disable() - This function provides a mechanism to disable ZFortify
  598. // without recompiling all the sourcecode. It can only be called, though,
  599. // when there is no memory on the ZFortify new'd list. (Ideally, at the 
  600. // start of the program before any memory has been allocated). If you
  601. // call this function when there IS memory on the ZFortify new'd list,
  602. // it will issue an error, and ZFortify will not be disabled.
  603. int ZFORTIFY_STORAGE
  604. ZFortify_Disable(char *file, unsigned long line)
  605. {
  606.     int result;
  607.     ZFORTIFY_LOCK();
  608.  
  609.     if(st_Head)
  610.     {
  611.         sprintf(st_Buffer, "ZFortify: %s.%d\n", file, line);
  612.         st_Output(st_Buffer);
  613.         st_Output("         ZFortify_Disable failed\n");
  614.         st_Output("         (because there is memory on the ZFortify memory list)\n");
  615.     
  616.         ZFortify_OutputAllMemory(file, line);
  617.         result = 0;            
  618.     }
  619.     else
  620.     {
  621.         st_Disabled = 1;
  622.         result = 1;
  623.     }
  624.   
  625.     ZFORTIFY_UNLOCK();
  626.     return(result);
  627. }
  628.  
  629. // Check a block's header and fortifications.
  630. static int
  631. CheckBlock(struct Header *h, char *file, unsigned long line)
  632. {   
  633.     unsigned char *ptr = (unsigned char *)h;
  634.     int result = 1;
  635.  
  636.     if(!IsHeaderValid(h))
  637.     {
  638.         sprintf(st_Buffer, "\nZFortify: %s.%ld\n         Invalid pointer or corrupted header detected (%p)\n",
  639.                             file, line, ptr + sizeof(struct Header) + ZFORTIFY_BEFORE_SIZE);
  640.         st_Output(st_Buffer);
  641.         OutputLastVerifiedPoint();
  642.         return(0);
  643.     }
  644.  
  645.     if(!CheckFortification(ptr + sizeof(struct Header), ZFORTIFY_BEFORE_VALUE, ZFORTIFY_BEFORE_SIZE))
  646.     {
  647.         sprintf(st_Buffer, "\nZFortify: %s.%ld\n         Memory overrun detected before block\n",
  648.                             file, line);
  649.         st_Output(st_Buffer);
  650.  
  651.         sprintf(st_Buffer,"         (%p,%ld,%s.%ld)\n", ptr + sizeof(struct Header) + ZFORTIFY_BEFORE_SIZE,
  652.                           (unsigned long)h->Size, h->File, h->Line);
  653.         st_Output(st_Buffer);
  654.     
  655.         OutputFortification(ptr + sizeof(struct Header), ZFORTIFY_BEFORE_VALUE, ZFORTIFY_BEFORE_SIZE);
  656.         OutputLastVerifiedPoint();
  657.         result = 0;
  658.     }
  659.  
  660.     if(!CheckFortification(ptr + sizeof(struct Header) + ZFORTIFY_BEFORE_SIZE + h->Size,
  661.                             ZFORTIFY_AFTER_VALUE, ZFORTIFY_AFTER_SIZE))
  662.     {
  663.         sprintf(st_Buffer, "\nZFortify: %s.%ld\n         Memory overrun detected after block\n",
  664.                             file, line);
  665.         st_Output(st_Buffer);
  666.  
  667.         sprintf(st_Buffer,"         (%p,%ld,%s.%ld)\n",
  668.                         ptr + sizeof(struct Header) + ZFORTIFY_BEFORE_SIZE,
  669.                         (unsigned long)h->Size, h->File, h->Line);
  670.         st_Output(st_Buffer);
  671.  
  672.         OutputFortification(ptr + sizeof(struct Header) + ZFORTIFY_BEFORE_SIZE + h->Size,
  673.                             ZFORTIFY_AFTER_VALUE, ZFORTIFY_AFTER_SIZE);
  674.         OutputLastVerifiedPoint();
  675.         result = 0;
  676.     }
  677.  
  678.     return(result);    
  679. }
  680.  
  681. // Checks if the _size_ bytes from _ptr_ are all set to _value_
  682. static int 
  683. CheckFortification(unsigned char *ptr, unsigned char value, size_t size)
  684. {
  685.     while(size--)
  686.         if(*ptr++ != value)
  687.             return(0);
  688.  
  689.     return(1);      
  690. }
  691.  
  692. // Set the _size_ bytes from _ptr_ to _value_.
  693. static void 
  694. SetFortification(unsigned char *ptr, unsigned char value, size_t size)
  695. {
  696.     memset(ptr, value, size);
  697. }
  698.  
  699. // Output the corrupted section of the fortification
  700. static void
  701. OutputFortification(unsigned char *ptr, unsigned char /*value*/, size_t size)
  702. {
  703.     unsigned long offset, column;
  704.     char    ascii[17];
  705.  
  706.     st_Output("Address     Offset Data");
  707.  
  708.     offset = 0;
  709.     column = 0;
  710.  
  711.     while(offset < size)
  712.     {
  713.         if(column == 0)
  714.         {
  715.             sprintf(st_Buffer, "\n%8p %8d ", ptr, offset);
  716.             st_Output(st_Buffer);
  717.         }
  718.  
  719.         sprintf(st_Buffer, "%02x ", *ptr);
  720.         st_Output(st_Buffer);
  721.  
  722.         ascii[ column ] = isprint( *ptr ) ? char(*ptr) : char(' ');
  723.         ascii[ column + 1 ] = '\0';
  724.  
  725.         ptr++;
  726.         offset++;
  727.         column++;
  728.  
  729.         if(column == 16)
  730.         {
  731.             st_Output( "   \"" );
  732.             st_Output( ascii );
  733.             st_Output( "\"" );
  734.             column = 0;
  735.         }
  736.     }
  737.  
  738.     if ( column != 0 )
  739.     {
  740.         while ( column ++ < 16 )
  741.         {
  742.             st_Output( "   " );
  743.         }
  744.         st_Output( "   \"" );
  745.         st_Output( ascii );
  746.         st_Output( "\"" );
  747.     }
  748.  
  749.     st_Output("\n");
  750. }
  751.  
  752. // Returns true if the supplied pointer does indeed point to a real Header
  753. static int 
  754. IsHeaderValid(struct Header *h)                                
  755. {
  756.     return(!ChecksumHeader(h));
  757. }
  758.  
  759. // Updates the checksum to make the header valid
  760. static void 
  761. MakeHeaderValid(struct Header *h)
  762. {
  763.     h->Checksum = 0;
  764.     h->Checksum = -ChecksumHeader(h);
  765. }
  766.  
  767. // Calculate (and return) the checksum of the header. (Including the Checksum
  768. // variable itself. If all is well, the checksum returned by this function should
  769. // be 0.
  770. static int 
  771. ChecksumHeader(struct Header *h)
  772. {
  773.     int c, checksum, *p;
  774.   
  775.     for(c = 0, checksum = 0, p = (int *)h; c < sizeof(struct Header)/sizeof(int); c++)
  776.         checksum += *p++;  
  777.     
  778.     return(checksum);
  779. }                  
  780.  
  781. // Examines the new'd list to see if the given header is on it.
  782. static int 
  783. IsOnList(struct Header *h)
  784. {
  785.     struct Header *curr;
  786.   
  787.     curr = st_Head;
  788.     while(curr)
  789.     {
  790.         if(curr == h)
  791.             return(1);
  792.       
  793.         curr = curr->Next;
  794.     }
  795.  
  796.     return(0);
  797. }
  798.  
  799. // Output the header...
  800. static void
  801. OutputHeader(struct Header *h)
  802. {
  803.     sprintf(st_Buffer, "%11p %8ld %s.%ld (%d)\n",
  804.                         (unsigned char*)h + sizeof(struct Header) + ZFORTIFY_BEFORE_SIZE,
  805.                         (unsigned long)h->Size,
  806.                         h->File, h->Line, h->Scope);
  807.     st_Output(st_Buffer);
  808. }
  809.  
  810. // Hex and ascii dump the memory
  811. static void
  812. OutputMemory(struct Header *h)
  813. {
  814.     OutputFortification((unsigned char*)h + sizeof(struct Header) + ZFORTIFY_BEFORE_SIZE,
  815.                         0, h->Size);
  816. }
  817.  
  818. static void 
  819. OutputLastVerifiedPoint()
  820. {
  821.     sprintf(st_Buffer, "\nLast Verified point: %s.%ld\n", 
  822.                       st_LastVerifiedFile,
  823.                       st_LastVerifiedLine);
  824.     st_Output(st_Buffer);
  825. }
  826.  
  827. #ifdef AUTOMATIC_LOG_FILE
  828. // Automatic log file stuff!
  829.  
  830. // AutoLogFile class. There can only ever be ONE of these 
  831. // instantiated! It is a static class, which means that
  832. // it's constructor will be called at program initialization,
  833. // and it's destructor will be called at program termination.
  834. // We don't know if the other static class objects have been
  835. // constructed/destructed yet, but this pretty much the best
  836. // we can do with standard C++ language features.
  837. class AutoLogFile
  838. {
  839.     static FILE *fp;
  840.     static int   written_something;
  841.  
  842. public:
  843.     AutoLogFile()
  844.     {
  845.         written_something = 0;
  846.         ZFortify_SetOutputFunc(AutoLogFile::Output);
  847.         ZFortify_EnterScope("Program Initialization",0);
  848.     }
  849.  
  850.     static void Output(const char *s)
  851.     {
  852.         if(written_something == 0)
  853.         {
  854.             FIRST_ERROR_FUNCTION;
  855.             fp = fopen(LOG_FILENAME, "w");
  856.             if(fp)
  857.             {
  858.                 time_t t;
  859.                 time(&t);
  860.                 fprintf(fp, "ZFortify log started at %s\n", ctime(&t));
  861.                 written_something = 1;
  862.             }    
  863.         }
  864.  
  865.         if(fp)
  866.         {
  867.             fputs(s, fp);
  868.             fflush(fp);
  869.         }    
  870.     }
  871.     
  872.     ~AutoLogFile()
  873.     {
  874.         ZFortify_LeaveScope("Program Termination",0);
  875.         if(fp)
  876.         {
  877.             time_t t;
  878.             time(&t);
  879.             fprintf(fp, "\nZFortify log closed at %s\n", ctime(&t));
  880.             fclose(fp);
  881.             fp = 0;
  882.         }    
  883.     }
  884. };
  885.  
  886. FILE *AutoLogFile::fp = 0;
  887. int   AutoLogFile::written_something = 0;
  888.  
  889. static AutoLogFile Abracadabra;
  890.  
  891. #endif // AUTOMATIC_LOG_FILE
  892. #endif // ZFORTIFY
  893.  
  894.